#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

use std::fmt;

//----------------------------------------------------------------
pub const IMAGE_DOS_SIGNATURE: u16 = 0x5A4D;

#[derive(Debug, Copy, Clone)]
#[repr(C)]
// pub struct DosHeader {
//     pub e_magic: u16,
//     _unused: [u16; 29],
//     pub e_lfanew: u32,
// }
pub struct IMAGE_DOS_HEADER {
    pub e_magic: u16,
    pub e_cblp: u16,
    pub e_cp: u16,
    pub e_crlc: u16,
    pub e_cparhdr: u16,
    pub e_minalloc: u16,
    pub e_maxalloc: u16,
    pub e_ss: u16,
    pub e_sp: u16,
    pub e_csum: u16,
    pub e_ip: u16,
    pub e_cs: u16,
    pub e_lfarlc: u16,
    pub e_ovno: u16,
    pub e_res: [u16; 4],
    pub e_oemid: u16,
    pub e_oeminfo: u16,
    pub e_res2: [u16; 10],
    pub e_lfanew: u32,
}

//----------------------------------------------------------------

pub const IMAGE_NT_HEADERS_SIGNATURE: u32 = 0x00004550;

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct IMAGE_NT_HEADERS32 {
    pub Signature: u32,
    pub FileHeader: IMAGE_FILE_HEADER,
    pub OptionalHeader: IMAGE_OPTIONAL_HEADER32,
}

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct IMAGE_NT_HEADERS64 {
    pub Signature: u32,
    pub FileHeader: IMAGE_FILE_HEADER,
    pub OptionalHeader: IMAGE_OPTIONAL_HEADER64,
}

#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct IMAGE_FILE_HEADER {
    pub Machine: u16,
    pub NumberOfSections: u16,
    pub TimeDateStamp: u32,
    pub PointerToSymbolTable: u32,
    pub NumberOfSymbols: u32,
    pub SizeOfOptionalHeader: u16,
    pub Characteristics: u16,
}

pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC: u16 = 0x10b;
pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC: u16 = 0x20b;

// helper struct
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[repr(C)]
pub struct IMAGE_VERSION<T> {
    pub Major: T,
    pub Minor: T,
}

impl<T: fmt::Display> fmt::Debug for IMAGE_VERSION<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "\"{}.{}\"", self.Major, self.Minor)
    }
}
impl<T: fmt::Display> fmt::Display for IMAGE_VERSION<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}.{}", self.Major, self.Minor)
    }
}

#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct IMAGE_OPTIONAL_HEADER32 {
    pub Magic: u16,
    pub LinkerVersion: IMAGE_VERSION<u8>, // 2 b
    pub SizeOfCode: u32,
    pub SizeOfInitializedData: u32,
    pub SizeOfUninitializedData: u32,
    pub AddressOfEntryPoint: u32,
    pub BaseOfCode: u32,
    pub BaseOfData: u32,
    pub ImageBase: u32,
    pub SectionAlignment: u32,
    pub FileAlignment: u32,
    pub OperatingSystemVersion: IMAGE_VERSION<u16>,
    pub ImageVersion: IMAGE_VERSION<u16>,
    pub SubsystemVersion: IMAGE_VERSION<u16>,
    pub Win32VersionValue: u32,
    pub SizeOfImage: u32,
    pub SizeOfHeaders: u32,
    pub CheckSum: u32,
    pub Subsystem: u16,
    pub DllCharacteristics: u16,
    pub SizeOfStackReserve: u32,
    pub SizeOfStackCommit: u32,
    pub SizeOfHeapReserve: u32,
    pub SizeOfHeapCommit: u32,
    pub LoaderFlags: u32,
    pub NumberOfRvaAndSizes: u32,
    pub DataDirectory: [IMAGE_DATA_DIRECTORY; 16],
}
//----------------------------------------------------------------

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct IMAGE_DATA_DIRECTORY {
    pub VirtualAddress: u32,
    pub Size: u32,
}

pub const IMAGE_DIRECTORY_ENTRY_EXPORT: usize = 0;
pub const IMAGE_DIRECTORY_ENTRY_IMPORT: usize = 1;
pub const IMAGE_DIRECTORY_ENTRY_RESOURCE: usize = 2;
pub const IMAGE_DIRECTORY_ENTRY_EXCEPTION: usize = 3;
pub const IMAGE_DIRECTORY_ENTRY_SECURITY: usize = 4;
pub const IMAGE_DIRECTORY_ENTRY_BASERELOC: usize = 5;
pub const IMAGE_DIRECTORY_ENTRY_DEBUG: usize = 6;
pub const IMAGE_DIRECTORY_ENTRY_ARCHITECTURE: usize = 7;
pub const IMAGE_DIRECTORY_ENTRY_GLOBALPTR: usize = 8;
pub const IMAGE_DIRECTORY_ENTRY_TLS: usize = 9;
pub const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: usize = 10;
pub const IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: usize = 11;
pub const IMAGE_DIRECTORY_ENTRY_IAT: usize = 12;
pub const IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: usize = 13;
pub const IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: usize = 14;

pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES: usize = 16;

//----------------------------------------------------------------
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct IMAGE_OPTIONAL_HEADER64 {
    pub Magic: u16,
    pub LinkerVersion: IMAGE_VERSION<u8>,
    pub SizeOfCode: u32,
    pub SizeOfInitializedData: u32,
    pub SizeOfUninitializedData: u32,
    pub AddressOfEntryPoint: u32,
    pub BaseOfCode: u32,
    pub ImageBase: u64,
    pub SectionAlignment: u32,
    pub FileAlignment: u32,
    pub OperatingSystemVersion: IMAGE_VERSION<u16>,
    pub ImageVersion: IMAGE_VERSION<u16>,
    pub SubsystemVersion: IMAGE_VERSION<u16>,
    pub Win32VersionValue: u32,
    pub SizeOfImage: u32,
    pub SizeOfHeaders: u32,
    pub CheckSum: u32,
    pub Subsystem: u16,
    pub DllCharacteristics: u16,
    pub SizeOfStackReserve: u64,
    pub SizeOfStackCommit: u64,
    pub SizeOfHeapReserve: u64,
    pub SizeOfHeapCommit: u64,
    pub LoaderFlags: u32,
    pub NumberOfRvaAndSizes: u32,
    pub DataDirectory: [IMAGE_DATA_DIRECTORY; IMAGE_NUMBEROF_DIRECTORY_ENTRIES],
}

//----------------------------------------------------------------

pub const IMAGE_SIZEOF_SHORT_NAME: usize = 8usize;

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct IMAGE_SECTION_HEADER {
    pub Name: [u8; IMAGE_SIZEOF_SHORT_NAME],
    pub VirtualSize: u32,
    pub VirtualAddress: u32,
    pub SizeOfRawData: u32,
    pub PointerToRawData: u32,
    pub PointerToRelocations: u32,
    pub PointerToLinenumbers: u32,
    pub NumberOfRelocations: u16,
    pub NumberOfLinenumbers: u16,
    pub Characteristics: u32,
}

impl IMAGE_SECTION_HEADER {
    pub fn name(&self) -> Result<&str, std::str::Utf8Error> {
        std::str::from_utf8(&self.Name)
    }
}

pub const IMAGE_SCN_CNT_CODE: u32 = 0x00000020; // Section contains code. 含代码
pub const IMAGE_SCN_MEM_SHARED: u32 = 0x10000000; // Section is shareable. 可共享
pub const IMAGE_SCN_MEM_EXECUTE: u32 = 0x20000000; // Section is executable. 可执行
pub const IMAGE_SCN_MEM_READ: u32 = 0x40000000; // Section is readable. 可读
pub const IMAGE_SCN_MEM_WRITE: u32 = 0x80000000; // Section is writeable. 可写
